package com.coder.books.thinkinjava.containers;

import com.coder.util.CollectionData;
import com.coder.util.CountingGenerator;
import com.coder.util.Generated;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Random;
import java.util.Vector;

/**
 * 展示列表中的性能差异
 * {参数：100 500} 小的，以保持简短的构建测试
 *
 * @author yuhushuan
 * @date 2020/8/18 18:32
 */
public class ListPerformance {
    static Random random = new Random();
    static int reps = 1000;
    static List<Test<List<Integer>>> tests = new ArrayList<>();
    static List<Test<LinkedList<Integer>>> qTests = new ArrayList<>();

    static {
        tests.add(new Test<List<Integer>>("add") {

            @Override
            int test(List<Integer> container, TestParam tp) {
                int loops = tp.loops;
                int size = tp.size;
                for (int i = 0; i < loops; i++) {
                    container.clear();
                    for (int j = 0; j < size; j++) {
                        container.add(j);
                    }
                }
                return loops * size;
            }
        });

        tests.add(new Test<List<Integer>>("get") {
            @Override
            int test(List<Integer> container, TestParam tp) {
                int loops = tp.loops * reps;
                int size = container.size();
                for (int i = 0; i < loops; i++) {
                    container.get(random.nextInt(size));
                }
                return loops;
            }
        });

        tests.add(new Test<List<Integer>>("set") {
            @Override
            int test(List<Integer> container, TestParam tp) {
                int loops = tp.loops * reps;
                int size = container.size();
                for (int i = 0; i < loops; i++) {
                    container.set(random.nextInt(size), 47);
                }
                return loops;
            }
        });

        tests.add(new Test<List<Integer>>("iteradd") {
            @Override
            int test(List<Integer> container, TestParam tp) {
                final int LOOPS = 1000000;
                int half = container.size() / 2;
                ListIterator<Integer> it = container.listIterator(half);
                for (int i = 0; i < LOOPS; i++) {
                    it.add(47);
                }
                return LOOPS;
            }
        });

        tests.add(new Test<List<Integer>>("insert") {
            @Override
            int test(List<Integer> container, TestParam tp) {
                int loops = tp.loops;
                for (int i = 0; i < loops; i++) {
                    container.add(5, 47);
                }
                return loops;
            }
        });

        tests.add(new Test<List<Integer>>("remove") {
            @Override
            int test(List<Integer> container, TestParam tp) {
                int loops = tp.loops;
                int size = tp.size;
                for (int i = 0; i < loops; i++) {
                    container.clear();
                    container.addAll(new CollectionData<>(new CountingGenerator.Integer(), size));
                    while (container.size() > 5) {
                        container.remove(5);
                    }
                }
                return loops * size;
            }
        });

        // 测试队列行为
        qTests.add(new Test<LinkedList<Integer>>("addFirst") {
            @Override
            int test(LinkedList<Integer> container, TestParam tp) {
                int loops = tp.loops;
                int size = tp.size;
                for (int i = 0; i < loops; i++) {
                    container.clear();
                    for (int j = 0; j < size; j++) {
                        container.addFirst(j);
                    }
                }
                return loops * size;
            }
        });

        qTests.add(new Test<LinkedList<Integer>>("addLast") {
            @Override
            int test(LinkedList<Integer> container, TestParam tp) {
                int loops = tp.loops;
                int size = tp.size;
                for (int i = 0; i < loops; i++) {
                    container.clear();
                    for (int j = 0; j < size; j++) {
                        container.addLast(j);
                    }
                }
                return loops * size;
            }
        });

        qTests.add(new Test<LinkedList<Integer>>("rmFirst") {
            @Override
            int test(LinkedList<Integer> container, TestParam tp) {
                int loops = tp.loops;
                int size = tp.size;
                for (int i = 0; i < loops; i++) {
                    container.clear();
                    container.addAll(new CollectionData<>(new CountingGenerator.Integer(), size));
                    while (container.size() > 0) {
                        container.removeFirst();
                    }
                }
                return loops * size;
            }
        });

        qTests.add(new Test<LinkedList<Integer>>("rmLast") {
            @Override
            int test(LinkedList<Integer> container, TestParam tp) {
                int loops = tp.loops;
                int size = tp.size;
                for (int i = 0; i < loops; i++) {
                    container.clear();
                    container.addAll(new CollectionData<>(new CountingGenerator.Integer(), size));
                    while (container.size() > 0) {
                        container.removeLast();
                    }
                }
                return loops * size;
            }
        });
    }

    static class ListTester extends Tester<List<Integer>> {

        public ListTester(List<Integer> container, List<Test<List<Integer>>> tests) {
            super(container, tests);
        }

        // 每次测试前填满合适的尺寸
        @Override
        protected List<Integer> initialize(int size) {
            container.clear();
            container.addAll(new CollectionData<>(new CountingGenerator.Integer(), size));
            return container;
        }

        // 便利方法
        public static void run(List<Integer> list, List<Test<List<Integer>>> tests) {
            new ListTester(list, tests).timedTest();
        }

        public static void main(String[] args) {
            if (args.length > 0) {
                Tester.defaultParams = TestParam.array(args);
            }
            // 只能在一个数组上做这两个测试
            Tester<List<Integer>> arrayTest =
                    new Tester<List<Integer>>(null, tests.subList(1, 3)) {
                        // 这将在每次测试之前调用。
                        // 它产生一个不可调整大小的基于数组的列表
                        @Override
                        protected List<Integer> initialize(int size) {
                            Integer[] ia = Generated.array(Integer.class,
                                    new CountingGenerator.Integer(), size);
                            return Arrays.asList(ia);
                        }
                    };
            arrayTest.setHeadline("Array as List");
            arrayTest.timedTest();
            Tester.defaultParams = TestParam.array(10, 5000, 100, 5000, 1000, 1000, 10000, 200);
            if (args.length > 0) {
                Tester.defaultParams = TestParam.array(args);
            }

            ListTester.run(new ArrayList<>(), tests);
            ListTester.run(new LinkedList<>(), tests);
            ListTester.run(new Vector<>(), tests);
            Tester.fieldWidth = 12;
            Tester<LinkedList<Integer>> qTest =
                    new Tester<LinkedList<Integer>>(new LinkedList<Integer>(), qTests);
            qTest.setHeadline("Queue tests");

        }
    }
}
